﻿using System;

namespace Tools
{
    public class Math
    {
        //1.计算延长点或者收缩点的点坐标
        public static Point Extend_or_Contract(Point pointA, Point pointB, double Length)
        {
            //向量AB
            double ABVector_X = pointB.X - pointA.X;
            double ABVector_Y = pointB.Y - pointA.Y;
            //向量AB的模 【x1*x2 + y1*y2】
            double ABNorm = Vector.Norm(ABVector_X, ABVector_Y);
            //长度*AB的单位向量 单位向量 = 向量 / 向量的模 
            double UnitVectorc_X = Length * (ABVector_X / ABNorm);
            double UnitVectorc_Y = Length * (ABVector_Y / ABNorm);
            //向量AB的长度+单位向量;
            double ALVector_X = ABVector_X + UnitVectorc_X;
            double ALVector_Y = ABVector_Y + UnitVectorc_Y;
            //向量AL的L点的坐标
            double NewPoint_X = pointA.X + ALVector_X;
            double NewPoint_Y = pointA.Y + ALVector_Y;
            Console.WriteLine("该点的坐标是:<" + NewPoint_X + "," + NewPoint_Y + ">");
            Point point = new Point(NewPoint_X, NewPoint_Y);
            return point;
        }
        //2.计算偏移（平移）后的点坐标
        public static Point Offset(Point pointA, double Offset)
        {
            double NewPoint_X = pointA.X + Offset;
            double NewPoint_Y = pointA.Y;
            Console.WriteLine("该点的坐标是:<" + NewPoint_X + "," + NewPoint_Y + ">");
            Point point = new Point(NewPoint_X, NewPoint_Y);
            return point;
        }
        //3.旋转角
        public static Point Rotation(Point pointA, Point pointB, double length, double angle)
        {
            Vector vectorAB = new Vector(pointB.X - pointA.X, pointB.Y - pointA.Y);
            //旋转后的向量 cos*x-sin*y  sin*x+cos*y 
            double NewVector_X = (System.Math.Cos(System.Math.PI / 180 * angle) * vectorAB.X) - (System.Math.Sin(System.Math.PI / 180 * angle) * vectorAB.Y);
            double NewVector_Y = (System.Math.Sin(System.Math.PI / 180 * angle) * vectorAB.X) + (System.Math.Cos(System.Math.PI / 180 * angle) * vectorAB.Y);
            //长度向量（半径向量的长度）=长度 * 旋转后的向量的单位向量;单位向量 = 向量 / 向量的模
            double UnitVectorc_X = length * NewVector_X / Vector.Norm(vectorAB.X, vectorAB.Y);
            double UnitVectorc_Y = length * NewVector_Y / Vector.Norm(vectorAB.X, vectorAB.Y);
            //终点坐标 起点+半径向量长度
            double NewPoint_X = System.Math.Round(UnitVectorc_X + pointA.X,2);
            double NewPoint_Y = System.Math.Round(UnitVectorc_Y + pointA.Y,2);
            Console.WriteLine("该点的坐标是:<" + NewPoint_X + "," + NewPoint_Y + ">");
            Point point = new Point(NewPoint_X, NewPoint_Y);
            return point;
        }
        //4.法向量（符合右手螺旋法则）
        public static Vector NormalVector(Point pointA, Point pointB, Point pointC)
        {
            //计算向量AB,AC的模
            Vector vectorAB = new Vector(pointB.X - pointA.X, pointB.Y - pointA.Y, pointB.Z - pointA.Z);
            Vector vectorAC = new Vector(pointC.X - pointA.X, pointC.Y - pointA.Y, pointC.Z - pointA.Z);
            double ABNorm = Vector.Norm(vectorAB.X, vectorAB.Y, vectorAB.Z);
            double ACNorm = Vector.Norm(vectorAC.X, vectorAC.Y, vectorAC.Z);
            //判断零向量
            if (ABNorm == 0 || ACNorm == 0)
            {
                Console.WriteLine("输入的坐标有误，请输入有效坐标！");
            }
            //判断三点共线
            if (Point.Collineation(vectorAB.X, vectorAB.Y, vectorAB.Z, vectorAC.X, vectorAC.Y, vectorAC.Z))
            {
                Console.WriteLine("三点共线，请输入有效坐标！");
            }
            //计算法向量
            double NormalVector_X = (vectorAB.X * vectorAC.Z) - (vectorAB.Z * vectorAC.Y);
            double NormalVector_Y = (vectorAB.X * vectorAC.Z) - (vectorAB.Z * vectorAC.X);
            double NormalVector_Z = (vectorAB.X * vectorAC.Y) - (vectorAB.Y * vectorAC.X);
            Console.WriteLine("法向量的坐标:<" + NormalVector_X + "," + NormalVector_Y + "," + NormalVector_Z + ">");
            Vector vector = new Vector(NormalVector_X, NormalVector_Y, NormalVector_Z);
            return vector;
        }

        //5.两向量相交
        public static Point VectorIntersection(Point pointA, Point pointB, Point pointC, Point pointD)
        {
            //计算向量AB,CD,AC,AD,BC,BD
            Vector vectorAB = new Vector(pointB.X - pointA.X, pointB.Y - pointA.Y);
            Vector vectorCD = new Vector(pointD.X - pointC.X, pointD.Y - pointC.Y);
            //判断两点共线 (x1 * y2 - x2 * y1)
            if (!Point.Collineation(vectorAB.X, vectorAB.Y, vectorCD.X, vectorCD.Y))
            {
                double A = pointB.Y - pointA.Y;
                double B = pointA.X - pointB.X;
                double C = pointB.X * pointA.Y - pointB.Y * pointA.X;
                double a = pointD.Y - pointC.Y;
                double b = pointC.X - pointD.X;
                double c = pointD.X * pointC.Y - pointD.Y * pointC.X;

                if (B != 0)
                {
                    double NewPoint_X = System.Math.Round((B * c - b * C) / (A * b - a * B), 2);
                    double NewPoint_Y = System.Math.Round((-A * NewPoint_X - C) / B, 2);
                    Console.WriteLine("该点的坐标是:<" + NewPoint_X + "," + NewPoint_Y + ">");
                    Point point = new Point(NewPoint_X, NewPoint_Y);
                    return point;
                }
                else
                {
                    double NewPoint_Y = System.Math.Round((a * C - A * c) / (A * b - a * B), 2);
                    double NewPoint_X = System.Math.Round((-B * NewPoint_Y - C) / A, 2);
                    Console.WriteLine("该点的坐标是:<" + NewPoint_X + "," + NewPoint_Y + ">");
                    Point point = new Point(NewPoint_X, NewPoint_Y);
                    return point;
                }
            }
            else
            {
                Console.WriteLine("两点共线！");
                return null;
            }
            
        }

        //6.求圆与点切点
        public static Point[] TangentPoint(Point CenterPoint, Point pointA, double Radius)
        {
            //点与圆心的距离
            double d = System.Math.Sqrt(System.Math.Pow(CenterPoint.X - pointA.X, 2) + System.Math.Pow(CenterPoint.Y - pointA.Y, 2));
            if (d < Radius)
            {
                Console.WriteLine("点不在圆外");
                return null;
            }
            //1.计算向量OE
            Vector vectorOE = new Vector(pointA.X - CenterPoint.X, pointA.Y - CenterPoint.Y);

            //2.利用OE的单位向量求向量OF 【OE/OE的模】* 半径【半径为OF的长度】 
            Vector vector = new Vector();
            vector.X = vectorOE.X * Radius / Vector.Norm(vectorOE.X, vectorOE.Y);
            vector.Y = vectorOE.Y * Radius / Vector.Norm(vectorOE.X, vectorOE.Y);

            //3. 求切点和OE的角度 OF的长度/OE的长度的cos

            double Angle = System.Math.Acos(Radius / Vector.Norm(vectorOE.X, vectorOE.Y)) * 180 / System.Math.PI;   //得到旋转角度
            //4.调用工具类第三小题的旋转角度的方法计算切点
            Point point =  Rotation(CenterPoint, new Point(CenterPoint.X + vector.X, CenterPoint.Y + vector.Y), Radius, Angle);
            Point point1 = Rotation(CenterPoint, new Point(CenterPoint.X + vector.X, CenterPoint.Y + vector.Y), Radius, -Angle);
            Point[] points = new Point[2];
            points[0] = point;
            points[1] = point1;
            return points;
        }

        //7.求圆与直线的交点
        public static Point[] Intersection(Point CenterPoint, Point pointA, Point pointB, double Radius)
        {
            //VextorAB
            Vector vectorAB = new Vector(pointB.X - pointA.X, pointB.Y - pointA.Y);
            //直线AB的直线一般式 Ax + By + C = 0 ，A = Y2 - Y1 ，B = X1 - X2 ，C = X2 * Y1 - X1 * Y2
            double A = pointB.Y - pointA.Y;
            double B = pointA.X - pointB.X;
            double C = pointB.X * pointA.Y - pointA.X * pointB.Y;
            //圆心到直线的距离
            double d = System.Math.Abs(A * CenterPoint.X + B * CenterPoint.Y + C) / Vector.Norm(A, B);
            //圆心在AB的垂点
            double PendantPoint_X, PendantPoint_Y;
            //AB和圆的交点
            double IntersectionA_X, IntersectionA_Y, IntersectionB_X, IntersectionB_Y;
            //判断直线和圆是否有交点
            if (d == Radius)
            {
                //圆心在AB的垂点
                PendantPoint_Y = (C * vectorAB.X + A * vectorAB.X * CenterPoint.X + A * vectorAB.Y * CenterPoint.Y) / (A * vectorAB.Y - B * vectorAB.X);
                PendantPoint_X = CenterPoint.X - System.Math.Sqrt((d + CenterPoint.Y - PendantPoint_Y) * (d - CenterPoint.Y - PendantPoint_Y));
                Console.WriteLine("AB和圆相切，有一个交点为:<" + PendantPoint_X + "," + PendantPoint_Y + ">");
                Point[] points = new Point[1];
                points[0] = new Point(PendantPoint_X, PendantPoint_Y);
                return points;
            }
            else if (d < Radius)
            {
                //圆心在AB的垂点
                PendantPoint_Y = (C * vectorAB.X + A * vectorAB.X * CenterPoint.X + A * vectorAB.Y * CenterPoint.Y) / (A * vectorAB.Y - B * vectorAB.X);
                PendantPoint_X = CenterPoint.X - System.Math.Sqrt((d + CenterPoint.Y - PendantPoint_Y) * (d - CenterPoint.Y - PendantPoint_Y));
                //圆心在AB上垂点到AB和圆的交点的距离
                double Distance = System.Math.Sqrt(Radius * Radius - d * d);
                //VectorAB的单位向量
                double ABUnitVector_X = vectorAB.X / Vector.Norm(vectorAB.X, vectorAB.Y);
                double ABUnitVector_Y = vectorAB.Y / Vector.Norm(vectorAB.X, vectorAB.Y);
                IntersectionA_X = PendantPoint_X + Distance * ABUnitVector_X;
                IntersectionA_Y = PendantPoint_Y + Distance * ABUnitVector_Y;
                IntersectionB_X = PendantPoint_X - Distance * ABUnitVector_X;
                IntersectionB_Y = PendantPoint_Y - Distance * ABUnitVector_Y;
                Console.WriteLine("AB和圆相交，有两个交点，分别是:<" + IntersectionA_X + "," + IntersectionA_Y + ">,<" + IntersectionB_X + "," + IntersectionB_Y + ">");
                Point[] points = new Point[2];
                points[0] = new Point(IntersectionA_X, IntersectionA_Y);
                points[1] = new Point(IntersectionB_X, IntersectionB_Y);
                return points;
            }
            else
            {
                Console.WriteLine("当前圆和直线没有交点！！");
                return null;
            }
        }
        //8.求圆与任意一点的切线的方向角
        public static double DirectionAngle(Point CenterPoint, Point pointA, double Radius)
        {
            //圆点(a,b)到点A(x,y)的距离 (a-x)^+(b-y)^开根
            double d = System.Math.Sqrt((CenterPoint.X - pointA.X) * (CenterPoint.X - pointA.X) + (CenterPoint.Y - pointA.Y) * (CenterPoint.Y - pointA.Y));
            //判断点在圆上的位置
            if (d > Radius)
            {
                Console.WriteLine("该点不在圆上！！");
                
                return 0;
            }
            double Angle;
            //是否存在斜率
            if (CenterPoint.X == pointA.X)
            {
                Angle = 0;
            }
            else
            {
                //计算圆点到点A的线段的斜率 (y1-y0)/(x1-x0)
                double K = (pointA.Y - CenterPoint.Y) / (pointA.X - CenterPoint.X);
                if (K == 0)
                {
                    Angle = 90;
                }
                else
                {
                    //角度转弧度：π/180 * 角度
                    Angle = System.Math.Atan(1 / K) * 180 / System.Math.PI;
                }
            }
            Console.WriteLine("点A<" + pointA.X + "," + pointA.Y + ">的切线方向角为:" + Angle + "度。");
            return Angle;
        }
    }
}
